﻿unit uMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Buttons, ComCtrls, Menus, Generics.Collections,
  uChoices, CheckLst;

type
  TfrmMain = class(TForm)
    StaticText1: TStaticText;
    sb: TStatusBar;
    st: TStaticText;
    Timer1: TTimer;
    od: TOpenDialog;
    PopupMenu1: TPopupMenu;
    sdfg1: TMenuItem;
    pbStatus: TProgressBar;
    btnAssociate: TSpeedButton;
    btnCancelFileAssociation: TSpeedButton;
    procedure cbClick(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure btnAssociateClick(Sender: TObject);
    procedure btnCancelFileAssociationClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure Next;
    procedure Finish;
    procedure clearCheckboxes(c: TCheckListBox );
    function calculateResultIntegerListToCheckBoxList( il: TList<Integer>; c: TCheckListBox ): Real;
    function calculateResultNumber( a: Byte; index: Integer ): Real;
    function getStatus: String;
    procedure Start;
    procedure Shuffle(cs: TList<TChoice>);
  end;

var
  frmMain: TfrmMain;
  f,ef:textfile;
  a,b,s:string;
  l:byte absolute s;
  la:byte absolute a;
  lb:byte absolute b;
  n,e:byte;
  m:Real;
  t:TTime;
  choices, bad: TList<TChoice>;
  currentIndex: Integer;
  question: TChoice;
  FileName: String;
  frmModal: TForm;
  omitRandomization: Boolean = false;
implementation

uses uRandom, UBoolForm, uMultiSelect, uMultiError, uBoolError, uMark, Registry;

{$R *.dfm}

procedure TfrmMain.Finish;
begin

end;

function TfrmMain.getStatus: String;
begin
  Result := 'Вгадано '+FloatToStr(m)+' з '+inttostr(n)+'.';
end;

procedure TfrmMain.Next;
var
  dm: Real;
  bfn: String;
begin
  if question.kind = 'm' then begin
    dm := calculateResultIntegerListToCheckBoxList( TMultipleChoice(question).correctAnswer, frmMultiSelect.clbChoices );
  end else
    dm := calculateResultNumber( TSingleChoice(question).correctAnswer, frmBool.rgChoices.ItemIndex);
  if dm > 0.9 then
    Messagebox(0,'Вітаю! Ви вгадали!','Окей!',64+$2000)
  else begin
    bad.Add( question );
    Messagebox(0,'...щось не те','Oops...',16+$2000);
    if question.kind = 'm' then begin
      frmMultiError.stDescription.Caption := TMultipleChoice(question).description;
      frmMultiError.clbChoices.Items.Text := TMultipleChoice(question).options;
      frmMultiError.clbCorrect.Items.Text := TMultipleChoice(question).options;
      TChoicesUtil.ConvertIntegerListToCheckBoxList( TMultipleChoice(question).correctAnswer, frmMultiError.clbCorrect );
      TChoicesUtil.CopyCheckboxList(  frmMultiSelect.clbChoices, frmMultiError.clbChoices );
      frmMultiError.Caption := 'Comparison of your answer and correct answer to test question #' + IntToStr(currentIndex + 1);

      frmMultiError.showModal();
    end else begin
      frmBoolError.stDescription.Caption := TSingleChoice(question).description;
      frmBoolError.rgChoices.Items.Text := TSingleChoice(question).options;
      frmBoolError.rgCorrect.Items.Text := TSingleChoice(question).options;
      frmBoolError.rgCorrect.ItemIndex := TSingleChoice(question).correctAnswer;
      frmBoolError.rgChoices.ItemIndex := frmBool.rgChoices.ItemIndex;
      frmBoolError.Caption := 'Comparison of your answer and correct answer to test question #' + IntToStr(currentIndex + 1);
      frmBoolError.ShowModal();
    end;
  end;
  m := m + dm;
  sb.SimpleText:=getStatus;
  frmModal.Hide();

  currentIndex := currentIndex + 1;
  pbStatus.Position := currentIndex;

  if currentIndex = choices.Count then begin
    if bad.Count > 0 then begin
      if FileExists('bad.sf') then
        bfn := 'bad' + RandomString(4) + '.sf'
      else
        bfn := 'bad.sf';
      TChoicesUtil.SaveFile(bad, bfn);
    end;

    ShowMessage('Finish. Status: ' + getStatus);
    Messagebox(0,'Кінець','Все!',48+$2000);
    frmMark.mark.Text:=inttostr(round(12*(m/n)));
    frmMark.T.Caption:='Time\Час: ' + FormatDateTime('hh:nn:ss', t);
    frmMark.ShowModal;
    close;

    Halt;
  end;
  question := choices[ currentIndex ];
  if question.kind = 'm' then begin
    frmMultiSelect.stDescription.Caption := question.description;
    frmMultiSelect.clbChoices.Items.Text := question.options;
    clearCheckboxes(frmMultiSelect.clbChoices);
    frmMultiSelect.sb.SimpleText:= getStatus;
    frmModal := frmMultiSelect;
  end else begin
    frmBool.stDescription.Caption := question.description;
    if question.kind = 'b' then
      frmBool.rgChoices.Items.Text := 'True'#13#10'False'
    else
      frmBool.rgChoices.Items.Text := question.options;
    frmBool.rgChoices.ItemIndex := -1;
    frmBool.sb.SimpleText:=getStatus;
    frmModal := frmBool;
  end;
  frmModal.Caption := 'Test question #' + IntToStr(currentIndex + 1);

  frmModal.Show();
end;

procedure TfrmMain.clearCheckboxes(c: TCheckListBox);
var
  i: Integer;
begin
  for i := 0 to c.Items.Count - 1 do
    c.Checked[i] := False;
end;

procedure TfrmMain.btnAssociateClick(Sender: TObject);
begin
  try
    CreateSalesforceFileAssociation();
  except on E: ERegistryException do
    ShowMessage('Not enough rights to write to registry.'#13#10'Please rerun as administrator');
  end;
end;

procedure TfrmMain.btnCancelFileAssociationClick(Sender: TObject);
var
  Response, Exists, Removed: String;
begin
  Response := CancelSalesforceFileAssociation();
  Exists := Copy(Response, 1, 3);
  Removed := Copy(Response, 4, 3);
  //ShowMessage('Response: ' + Response);
  if Exists = '000' then
    ShowMessage('Error: Program has not been associated or file association has been already canceled')
  else
  if Removed = '000' then
    ShowMessage('Not enough rights to write to registry.'#13#10'Please rerun as administrator');
end;

function TfrmMain.calculateResultIntegerListToCheckBoxList( il: TList<Integer>; c: TCheckListBox ): Real;
var
  i, sum: Integer;
begin
  sum := c.Items.Count;
  if sum < 1 then begin
    Result := 0;
    Exit;
  end;

  for i := 0 to c.Items.Count - 1 do begin
    if c.Checked[i] = il.Contains(i) then
      sum := sum + 1
    else
      sum := sum - 1;
  end;
  Result := sum / (c.Items.Count shl 1);
end;

function TfrmMain.calculateResultNumber(a: Byte; index: Integer): Real;
begin
  if a = index then
    Result := 1
  else
    Result := 0;
end;

procedure TfrmMain.cbClick(Sender: TObject);
begin
 close;
end;

procedure TfrmMain.Shuffle(cs: TList<TChoice>);
var
  i: Integer;
begin
  for i := cs.Count - 1 downto 1 do
    cs.Exchange( i, Random( i + 1 ) );
end;

procedure TfrmMain.Start;
var
  i: Integer;
begin
  Randomize;
  t := 0;
  s:=paramstr(1);
  if fileexists(s) then
    FileName := s
  else
    if od.Execute then
      FileName := od.FileName
    else
      Halt;
  for i := 2 to ParamCount do
    if LowerCase( ParamStr(i) ) = 'o' then
      omitRandomization := True;

  choices := TChoicesUtil.LoadFromFile( FileName );
  if choices.Count = 0 then begin
    Messagebox(0,'Empty file','sorry',48+$2000);
    Halt;
  end;

  if not omitRandomization then
    Shuffle(choices);
  bad := TList<TChoice>.Create();
  currentIndex := 0;
  n := choices.Count;
  pbStatus.Max := n;
  pbStatus.Position := currentIndex;
  question := choices[ currentIndex ];
  if question.kind = 'm' then begin
    frmMultiSelect.stDescription.Caption := question.description;
    frmMultiSelect.clbChoices.Items.Text := question.options;
    frmMultiSelect.sb.SimpleText:=getStatus;
    frmModal := frmMultiSelect;
  end else begin
    frmBool.stDescription.Caption := question.description;
    if question.kind = 'b' then
      frmBool.rgChoices.Items.Text := 'True'#13#10'False'
    else
      frmBool.rgChoices.Items.Text := question.options;
    frmModal := frmBool;
    frmBool.sb.SimpleText:=getStatus;
    frmModal := frmBool;
  end;
  sb.SimpleText:=getStatus;
  frmModal.Caption := 'Test question #' + IntToStr(currentIndex + 1);
  frmModal.Show();

end;

procedure TfrmMain.Timer1Timer(Sender: TObject);
var
  h, m, s, l : Word;
begin
  if Visible then begin
    t:=t+1/3600/24;
    DecodeTime(t, h, m, s, l);
    st.Caption:='Time\Час: ' + FormatDateTime('hh:nn:ss', t);
  end;
end;

end.
